home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / sw / serv_comm.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  16.4 KB  |  611 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include "comm.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <stream.h>
  21. #include <sys/socket.h>
  22. #include <sys/time.h>
  23. #include <netdb.h>
  24. #include <errno.h>
  25. #include <signal.h>
  26. #include <unistd.h>
  27. #include <bstring.h>
  28. // ADDED 08/11/93:
  29. #include <CC/osfcn.h>
  30.  
  31. #define    STATUS_NOCONNECTION    -1
  32. #define    STATUS_READY        0
  33.  
  34. static TeamInfo        teamStatus[NUMTEAMS];    // team information
  35. static PlayerInfo    playerInfo[MAXPLAYERS];    // player information
  36. static int        playerAlive[MAXPLAYERS];// TRUE if player alive
  37. static Team        playerFlag[MAXPLAYERS];    // which flag player has
  38.  
  39. #define    FS        FIELDSIZE
  40. #define    BR        (1.5 * BASERADIUS)
  41. static float        teamBasePos[NUMTEAMS][3] = {
  42.                 { -FS, -FS, FS },
  43.                 { FS, -FS, -FS },
  44.                 { -FS, FS, FS },
  45.                 { FS, FS, -FS } };
  46. static float        teamBaseSafety[NUMTEAMS][3] = {
  47.                 { -FS-BR, -FS-BR,  FS+BR },
  48.                 {  FS+BR, -FS-BR, -FS-BR },
  49.                 { -FS-BR,  FS+BR,  FS+BR },
  50.                 {  FS+BR,  FS+BR, -FS-BR } };
  51.  
  52. static int        connectFd,        // connection socket
  53.             maxFd,            // highest fd
  54.             directFd[MAXPLAYERS],    // stream sockets
  55.             statusFd[MAXPLAYERS];    // state of connection
  56. static int        currentConnection = -1;
  57.  
  58. static void        removePlayer(int);
  59. static void        serverStop(int);
  60.  
  61. static int        isAny(InAddr id)
  62. {
  63.   return (id.s_addr == INADDR_ANY);
  64. }
  65.  
  66. static int        lookupPlayer(NetId id)
  67. {
  68.   for (int i = 0; i < MAXPLAYERS; i++)
  69.     if (directFd[i] != -1 && NetId(playerInfo[i].id) == id)
  70.       return i;
  71.   return -1;
  72. }
  73.  
  74. static int        lookupPlayer(int fd)
  75. {
  76.   if (fd == -1) return -1;
  77.   for (int i = 0; i < MAXPLAYERS; i++)
  78.     if (fd == directFd[i])
  79.       return i;
  80.   return -1;
  81. }
  82.  
  83. static int        dread(int fd, void* b, int l)
  84. {
  85.   if (fd == -1) return 0;
  86.   currentConnection = fd;
  87.   int e = read(fd, b, l);
  88.   if (e < 0 || (e == 0 && l > 0)) {
  89.     int i;
  90.     if ((i = lookupPlayer(currentConnection)) != -1) {
  91.       if (e == 0 || errno == ECONNRESET || errno == EINTR || errno == EBADMSG)
  92.     removePlayer(i);
  93.       else if (errno != EAGAIN) {
  94.     if (e < 0) perror("error on dread");
  95.     else cerr << "zero length read\n";
  96.     serverStop(1);
  97.       }
  98.     }
  99.   }
  100.   currentConnection = -1;
  101.   return e;
  102. }
  103.  
  104. static int        dwrite(int fd, const void* b, int l)
  105. {
  106.   if (fd == -1) return 0;
  107.   currentConnection = fd;
  108.   int e = write(fd, b, l);
  109.   if (e < 0 || (e == 0 && l > 0)) {
  110.     int i;
  111.     if ((i = lookupPlayer(currentConnection)) != -1) {
  112.       if (e == 0 || errno == ECONNRESET || errno == EINTR || errno == EPIPE)
  113.     removePlayer(i);
  114.       else if (errno != EAGAIN) {
  115.     if (e < 0) perror("error on dwrite");
  116.     else cerr << "zero length write\n";
  117.     serverStop(1);
  118.       }
  119.     }
  120.   }
  121.   currentConnection = -1;
  122.   return e;
  123. }
  124.  
  125. static void        resetFlag(int i)
  126. {
  127.   teamStatus[i].state = (teamStatus[i].players == 0) ? FlagNoExist : FlagReady;
  128.   teamStatus[i].owner = NetId();
  129.   teamStatus[i].position[0] = teamBasePos[i][0];
  130.   teamStatus[i].position[1] = teamBasePos[i][1];
  131.   teamStatus[i].position[2] = teamBasePos[i][2];
  132. }
  133.  
  134. static int        defineWorld(void)
  135. {
  136.   for (int i = 0; i < NUMTEAMS; i++) {
  137.     teamStatus[i].team = Team(i);
  138.     teamStatus[i].players = 0;
  139.     teamStatus[i].won = 0;
  140.     teamStatus[i].lost = 0;
  141.     resetFlag(i);
  142.   }
  143.   for (i = 0; i < MAXPLAYERS; i++) {
  144.     playerFlag[i] = NoTeam;
  145.     playerAlive[i] = FALSE;
  146.   }
  147.   return 0;
  148. }
  149.  
  150. static int        serverStart(void)
  151. {
  152.   struct sockaddr_in    addr;
  153.  
  154.   addr.sin_family = AF_INET;
  155.   addr.sin_port = SERVERPORT;        // special 'port assigner' port
  156.   addr.sin_addr.s_addr = INADDR_ANY;
  157.  
  158.   /* now initialize things with me as server */
  159.   /* make connect server socket */
  160.   connectFd = socket(AF_INET, SOCK_STREAM, 0);
  161.   if (connectFd == -1) {
  162.     perror("couldn't make connect socket");
  163.     return -1;
  164.   }
  165.   if (bind(connectFd, (const void*)&addr, sizeof(addr)) == -1) {
  166.     perror("couldn't bind connect socket");
  167.     close(connectFd);
  168.     return -1;
  169.   }
  170.   if (listen(connectFd, 10) == -1) {
  171.     perror("couldn't make connect socket queue");
  172.     close(connectFd);
  173.     return -1;
  174.   }
  175.   maxFd = connectFd;
  176.  
  177.   for (int i = 0; i < MAXPLAYERS; i++) {    // no direct connections
  178.     directFd[i] = -1;
  179.     statusFd[i] = STATUS_NOCONNECTION;
  180.   }
  181.  
  182.   return 0;
  183. }
  184.  
  185. static void        serverStop(int exitCode)
  186. {
  187.   close(connectFd);
  188.   for (int i = 0; i < MAXPLAYERS; i++)
  189.     if (directFd[i] != -1)
  190.       close(directFd[i]);
  191.   exit(exitCode);
  192. }
  193.  
  194. static int        acceptDirect(int allow)
  195. {
  196.   // establish a new direct connection
  197.   struct sockaddr_in    addr;
  198.   int            fail = 0, fd, fd2, addr_len = sizeof(addr);
  199.  
  200.   fd = accept(connectFd, (void*)&addr, &addr_len);
  201.   if (fd == -1) {
  202.     perror("couldn't accept connect socket");
  203.     return -1;
  204.   }
  205.  
  206.   addr.sin_family = AF_INET;
  207.   addr.sin_port = 0;                // use any available port
  208.   addr.sin_addr.s_addr = INADDR_ANY;
  209.   addr_len = sizeof(addr);
  210.   fd2 = socket(AF_INET, SOCK_STREAM, 0);
  211.   if (fd2 == -1) fail = TRUE;
  212.   if (!fail && bind(fd2, &addr, sizeof(addr)) == -1) fail = TRUE;
  213.   if (!fail && getsockname(fd2, &addr, &addr_len) == -1) fail = TRUE;
  214.   if (fail || !allow) addr.sin_port = 0;    // error or too many players
  215.  
  216.   // send which port to use for connection
  217.   dwrite(fd, (void*)&addr.sin_port, sizeof(addr.sin_port));
  218.   close(fd);
  219.   if (fail || !allow) return -1;
  220.  
  221.   if (listen(fd2, 1) == -1) {
  222.     perror("making queue for direct connection");
  223.     close(fd2);
  224.     return -1;
  225.   }
  226.   addr_len = sizeof(addr);
  227.   fd = accept(fd2, (void*)&addr, &addr_len);
  228.   if (fd == -1) {
  229.     perror("making direct socket");
  230.     return -1;
  231.   }
  232.   close(fd2);
  233.   return fd;
  234. }
  235.  
  236. // get message
  237. static int        recvPacket(int fd, ServerPacket& packet)
  238. {
  239.   return (dread(fd, (void*)&packet, sizeof(packet)) == sizeof(packet));
  240. }
  241.  
  242. // send message to every player
  243. static void        broadcastPacket(ServerPacket& packet)
  244. {
  245.   packet.length = sizeof(ServerPacket) - sizeof(InAddr) - sizeof(int);
  246.   for (int i = 0; i < MAXPLAYERS; i++)
  247.     if (statusFd[i] == STATUS_READY)
  248.       dwrite(directFd[i], (void*)&packet, sizeof(packet));
  249. }
  250.  
  251. // send message to one player
  252. static void        sendPacket(int fd, ServerPacket& packet)
  253. {
  254.   packet.length = sizeof(ServerPacket) - sizeof(InAddr) - sizeof(int);
  255.   dwrite(fd, (void*)&packet, sizeof(packet));
  256. }
  257.  
  258. // send flag update to every player
  259. static void        sendTeamUpdate(Team team)
  260. {
  261.   ServerPacket p;
  262.   p.type = SwFlagUpdate;
  263.   p.any.flagUpdate.info = teamStatus[int(team)];
  264.   broadcastPacket(p);
  265. }
  266.  
  267. // return whose base a point is in
  268. static Team        whoseBase(float p[3])
  269. {
  270.   float dx, dy, dz;
  271.   for (int i = 0; i < NUMTEAMS; i++) {
  272.     dx = p[0] - teamBasePos[i][0],
  273.     dy = p[1] - teamBasePos[i][1],
  274.     dz = p[2] - teamBasePos[i][2];
  275.     if (dx * dx + dy * dy + dz * dz < BASERADIUS * BASERADIUS)
  276.       return Team(i);
  277.   }
  278.   return NoTeam;
  279. }
  280.  
  281. static void        grabFlag(int player, Team flagTeam)
  282. {
  283.   ServerPacket        msg;
  284.   SwFlagGrabbedMessage&    grabmsg = msg.any.flagGrabbed;
  285.  
  286.   // player now has a flag
  287.   playerFlag[player] = flagTeam;
  288.  
  289.   // set new team status
  290.   teamStatus[int(flagTeam)].state = FlagOnShip;
  291.   teamStatus[int(flagTeam)].owner = playerInfo[player].id;
  292.  
  293.   // tell everyone about grab
  294.   msg.type = SwFlagGrabbed;
  295.   grabmsg.grabber = playerInfo[player].id;
  296.   grabmsg.info = teamStatus[int(flagTeam)];
  297.   broadcastPacket(msg);
  298. }
  299.  
  300. static void        dropFlag(int player, Team flagTeam, float p[3])
  301. {
  302.   Team            b = whoseBase(p);
  303.   ServerPacket        msg;
  304.   SwFlagDroppedMessage&    dropmsg = msg.any.flagDropped;
  305.  
  306.   // player has no flag
  307.   playerFlag[player] = NoTeam;
  308.  
  309.   // set new team status
  310.   teamStatus[int(flagTeam)].state = FlagReady;
  311.   teamStatus[int(flagTeam)].owner = NetId();
  312.   if (b == NoTeam) {
  313.     teamStatus[int(flagTeam)].position[0] = p[0];
  314.     teamStatus[int(flagTeam)].position[1] = p[1];
  315.     teamStatus[int(flagTeam)].position[2] = p[2];
  316.   }
  317.   else {
  318.     // team A dropped team B's flag in team C's base -- move to safety position
  319.     teamStatus[int(flagTeam)].position[0] = teamBaseSafety[int(flagTeam)][0];
  320.     teamStatus[int(flagTeam)].position[1] = teamBaseSafety[int(flagTeam)][1];
  321.     teamStatus[int(flagTeam)].position[2] = teamBaseSafety[int(flagTeam)][2];
  322.   }
  323.  
  324.   // tell everyone about drop and new flag state
  325.   msg.type = SwFlagDropped;
  326.   dropmsg.dropper = playerInfo[player].id;
  327.   dropmsg.info = teamStatus[int(flagTeam)];
  328.   broadcastPacket(msg);
  329. }
  330.  
  331. static void        captureFlag(int player, Team flagTeam, Team captorTeam)
  332. {
  333.   ServerPacket        msg;
  334.   SwFlagCapturedMessage    &capturemsg = msg.any.flagCaptured;
  335.  
  336.   // update team scores
  337.   teamStatus[int(flagTeam)].lost += teamStatus[int(flagTeam)].players;
  338.   if (flagTeam != captorTeam)
  339.     teamStatus[int(captorTeam)].won += teamStatus[int(flagTeam)].players;
  340.  
  341.   // put captured flag back in it's base (and whoever had it doesn't now)
  342.   int p = lookupPlayer(teamStatus[flagTeam].owner);
  343.   if (p != -1) playerFlag[p] = NoTeam;
  344.   resetFlag(int(flagTeam));
  345.  
  346.   // tell everyone about drop and new flag state
  347.   msg.type = SwFlagCaptured;
  348.   capturemsg.captor = playerInfo[player].id;
  349.   capturemsg.flagTeam = teamStatus[int(flagTeam)];
  350.   capturemsg.captorTeam = teamStatus[int(captorTeam)];
  351.   broadcastPacket(msg);
  352. }
  353.  
  354. static void        addPlayer(void)
  355. {
  356.   int        fd;
  357.   ServerPacket    msg;
  358.  
  359.   for (int i = 0; i < MAXPLAYERS; i++)        // find open spot
  360.     if (statusFd[i] == STATUS_NOCONNECTION)
  361.       break;
  362.  
  363.   // establish a new direct connection
  364.   fd = acceptDirect(i != MAXPLAYERS);
  365.   if (fd == -1) return;
  366.  
  367.   // get join packet
  368.   if (!recvPacket(fd, msg)) {            // if can't get packet
  369.     close(fd);                    //  don't add player
  370.     return;
  371.   }
  372.   if (msg.type != SwJoin) {            // if not a join message
  373.     close(fd);                    //  reject connection
  374.     return;
  375.   }
  376.  
  377.   // set player information
  378.   playerInfo[i] = msg.any.join.p;        // store player data
  379.   playerAlive[i] = FALSE;            // start dead
  380.   playerFlag[i] = NoTeam;            // doesn't have a flag
  381.  
  382.   // record new connection
  383.   directFd[i] = fd;
  384.   if (directFd[i] > maxFd) maxFd = directFd[i];    // new max file descriptor
  385.   statusFd[i] = MAXPLAYERS + NUMTEAMS;        // I'm sending info
  386.  
  387.   // set team info.  if first player on a team, add team's flag
  388.   teamStatus[playerInfo[i].team].players++;    // add a player to the team
  389.   if (teamStatus[playerInfo[i].team].players == 1) {
  390.     teamStatus[playerInfo[i].team].won = 0;    // reset team's score
  391.     teamStatus[playerInfo[i].team].lost = 0;
  392.     resetFlag(playerInfo[i].team);
  393.     sendTeamUpdate(playerInfo[i].team);
  394.   }
  395.  
  396.   // tell everyone there's a new player
  397.   msg.type = SwAddPlayer;
  398.   msg.any.addPlayer.p = playerInfo[i];
  399.   broadcastPacket(msg);
  400. }
  401.  
  402. static void        removePlayer(int player)
  403. {
  404.   ServerPacket    msg;
  405.  
  406.   // remove tank from file descriptor list
  407.   close(directFd[player]);
  408.   directFd[player] = -1;
  409.   statusFd[player] = STATUS_NOCONNECTION;
  410.  
  411.   // tell everyone to remove player
  412.   msg.type = SwRemovePlayer;
  413.   msg.any.removePlayer.id = playerInfo[player].id;
  414.   broadcastPacket(msg);
  415.  
  416.   // set team info.  if last player on a team, remove team flag
  417.   teamStatus[playerInfo[player].team].players--; // remove player from the team
  418.   if (teamStatus[playerInfo[player].team].players == 0) {
  419.  
  420. //  determine if there are any more players left after this one is removed
  421.     for (int i=0, teams_left=0; i<NUMTEAMS; i++)
  422.         if (teamStatus[i].players != 0)
  423.             teams_left++;
  424.  
  425. //  if there are no more teams, bring down the server
  426.     if (!teams_left) {
  427.         serverStop(0);
  428.     } 
  429.     else {
  430.         resetFlag(playerInfo[player].team);
  431.         sendTeamUpdate(playerInfo[player].team);
  432.     }
  433.   }
  434.  
  435.   // check that player didn't have a flag
  436.   if (playerFlag[player] != NoTeam &&        // hmmm, player had a flag
  437.     teamStatus[int(playerFlag[player])].state != FlagNoExist) {
  438.     resetFlag(playerFlag[player]);
  439.     sendTeamUpdate(playerFlag[player]);
  440.   }
  441.  
  442.   playerAlive[player] = FALSE;
  443.   playerFlag[player] = NoTeam;
  444. }
  445.  
  446. static void        sendWorldInfo(int player)
  447. {
  448.   int        n = (MAXPLAYERS + NUMTEAMS) - statusFd[player];
  449.   ServerPacket    msg;
  450.  
  451.   msg.type = SwWorld;
  452.   if (statusFd[player] == STATUS_NOCONNECTION)    // this shouldn't happen
  453.     return;
  454.   if (statusFd[player] == STATUS_READY) {    // say we're done with world
  455.     msg.any.world.type = WorldNone;
  456.     msg.any.world.count = 0;
  457.   }
  458.   if (n < NUMTEAMS) {                // set team info
  459.     msg.any.world.type = WorldTeam;
  460.     msg.any.world.count = --statusFd[player];
  461.     msg.any.world.info.team = teamStatus[n];
  462.   }
  463.   else {                    // set player info
  464.     n -= NUMTEAMS;
  465.     while (n < MAXPLAYERS && directFd[n] == -1) {
  466.       statusFd[player]--;
  467.       n++;
  468.     }
  469.     if (n < MAXPLAYERS) {
  470.       msg.any.world.type = WorldPlayer;
  471.       msg.any.world.count = --statusFd[player];
  472.       msg.any.world.info.player = playerInfo[n];
  473.     }
  474.     else {
  475.       msg.any.world.type = WorldNone;
  476.       msg.any.world.count = 0;
  477.       statusFd[player] = STATUS_READY;
  478.     }
  479.   }
  480.   sendPacket(directFd[player], msg);        // send info
  481. }
  482.  
  483. static void        handleMessage(int player, ServerPacket& msg)
  484. {
  485.   if (player < 0 || player >= MAXPLAYERS)    // invalid player number
  486.     return;
  487.   switch (msg.type) {
  488.     case SwNone:
  489.     // do nothing
  490.     break;
  491.     case SwJoin:
  492.     // shouldn't get this.  it's handled in addPlayer()
  493.     break;
  494.     case SwQuit:
  495.     // remove player
  496.     removePlayer(player);
  497.     break;
  498.     case SwGetWorld:
  499.     // send more of current game state
  500.     sendWorldInfo(player);
  501.     break;
  502.     case SwAlive:
  503.     if (statusFd[player] == STATUS_READY)
  504.       playerAlive[player] = TRUE;
  505.     break;
  506.     case SwGrabFlag:
  507.     if (playerAlive[player] && playerFlag[player] == NoTeam &&
  508.             teamStatus[msg.any.grabFlag.team].state == FlagReady)
  509.       grabFlag(player, msg.any.grabFlag.team);
  510.     break;
  511.     case SwDropFlag:
  512.     if (playerAlive[player] && playerFlag[player] == msg.any.dropFlag.team)
  513.       dropFlag(player, msg.any.dropFlag.team, msg.any.dropFlag.position);
  514.     break;
  515.     case SwCaptureFlag:
  516.     if (playerAlive[player] &&
  517.             playerFlag[player] == msg.any.captureFlag.flagTeam)
  518.       captureFlag(player, msg.any.captureFlag.flagTeam,
  519.                     msg.any.captureFlag.captorTeam);
  520.     break;
  521.     case SwKilled: {
  522.     int victim = lookupPlayer(msg.any.killed.victim);
  523.     Team killerTeam = playerInfo[lookupPlayer(msg.any.killed.killer)].team,
  524.          victimTeam = playerInfo[victim].team;
  525.     if (playerAlive[victim])        // note the dead guy
  526.       playerAlive[victim] = FALSE;
  527.     broadcastPacket(msg);            // forward the message
  528.     teamStatus[int(victimTeam)].lost++;    // victim's team lost a point
  529.     if (killerTeam == victimTeam) {
  530.       teamStatus[int(killerTeam)].lost++;    // make that two
  531.     }
  532.     else {
  533.       teamStatus[int(killerTeam)].won++;    // killer team wins a point
  534.       sendTeamUpdate(killerTeam);
  535.     }
  536.     sendTeamUpdate(victimTeam);
  537.     break;
  538.       }
  539.     case SwHit:
  540.     // just forward the message
  541.     broadcastPacket(msg);
  542.     break;
  543.     case SwMessage:
  544.     // just forward the message
  545.     broadcastPacket(msg);
  546.     break;
  547.     default:
  548.     // shouldn't happen -- do nothing
  549.     break;
  550.   }
  551. }
  552.  
  553. static void        terminate_server(int ...)
  554. {
  555.   serverStop(0);
  556. }
  557.  
  558. static void        usage(char* pname)
  559. {
  560.   fprintf(stderr, "usage: %s\n", pname);
  561.   exit(1);
  562. }
  563.  
  564. static void        parse(int argc, char** argv)
  565. {
  566.   for (int i = 1; i < argc; i++)
  567.     if (argv[i][0] == '-') switch(argv[i][1]) {
  568.       default:
  569.     usage(argv[0]);
  570.     }
  571.     else usage(argv[0]);
  572. }
  573.  
  574. int            main(int argc, char** argv)
  575. {
  576.   fd_set        dread_set;
  577.  
  578.   parse(argc, argv);
  579.   if (defineWorld() < 0) return 1;
  580.   if (serverStart() < 0) return 1;
  581.  
  582.   signal(SIGINT, terminate_server);        // let user kill server
  583.   signal(SIGTERM, terminate_server);        // let user kill server
  584.   signal(SIGPIPE, SIG_IGN);            // don't die on SIGPIPE
  585.  
  586.   for (;;) {                    // loop forever
  587.     // wait for a message on any of my connections
  588.     FD_ZERO(&dread_set);
  589.     for (int i = 0; i < MAXPLAYERS; i++)
  590.       if (directFd[i] != -1)
  591.     FD_SET(directFd[i], &dread_set);
  592.     FD_SET(connectFd, &dread_set);
  593.     int nfound = select(maxFd+1, (FD_TYPE*)&dread_set, NULL, NULL, NULL);
  594.  
  595.     if (nfound > 0) {
  596.       if (FD_ISSET(connectFd, &dread_set))    // connection requested
  597.     addPlayer();
  598.       for (i = 0; i < MAXPLAYERS; i++)        // look for message from player
  599.     if (directFd[i] != -1 && FD_ISSET(directFd[i], &dread_set)) {
  600.       ServerPacket msg;
  601.       if (recvPacket(directFd[i], msg))
  602.         handleMessage(i, msg);
  603.     }
  604.     }
  605.     else if (nfound < 0) {            // something went wrong
  606.       perror("select error");
  607.       if (errno != EINTR) sleep(1);
  608.     }
  609.   }
  610. }
  611.